#include "Arvore.h"

/*------------------------
  Construtor da arvore...
------------------------*/
Arvore::Arvore()
{
    this->raiz = NULL;
}

/*------------------------
  Destrutor da arvore...
------------------------*/
Arvore::~Arvore()
{
    if (this->raiz != NULL) delete this->raiz;
}

/*--------------------------------
  Insere elemento raiz da arvore
--------------------------------*/
NoArvore* Arvore::inserirRaiz(char *elemento)
{
    if (this->raiz == NULL)
        this->raiz = new NoArvore();

    this->raiz->setNo(0, elemento);
    this->raiz->setNoPai(NULL);

    return this->raiz;
}

/*--------------------------------
  Retorna o elemento raiz da arvore
--------------------------------*/
NoArvore* Arvore::getRaiz()
{
    return this->raiz;
}


/*---------------------------------------
  Insere um elemento como filho do noPai
----------------------------------------*/
NoArvore* Arvore::inserirNo(NoArvore *noPai, const char *elemento)
{
    if (noPai == NULL) return NULL;
    
    return noPai->inserirFilho(elemento);
}

/*---------------------------------------
  Insere um no como filho do noPai
----------------------------------------*/
NoArvore* Arvore::inserirNo(NoArvore *noPai, NoArvore *noFilho)
{
    if (noPai == NULL) return NULL;
    
    return noPai->inserirSubArvore(noFilho);
}

/*-----------------------------------------------------
  Exibe todos elementos da arvore de forma hierarquica
------------------------------------------------------*/
void Arvore::exibirArvore(std::ostream& saida)
{
    saida << "\n\n";

    if (this->raiz == NULL)
    {
        std::cout << "Arvore vazia!!!" << std::endl;
        return;
    }

    std::list<NoArvore*>::reverse_iterator it;
    std::list<NoArvore*>::reverse_iterator it_rev;
    
    this->carregarFilaImpressao();

    bool imprimir = false;
        std::string marcador;

    for (it = this->mFilaImpressao.rbegin(); it != this->mFilaImpressao.rend(); it++)
    {
        int nivelAtual = (*it)->getNivel();
        int nivel = 0;
        int nivelAux   = (*it)->getNivel();
        bool entrou;      
        std::string proximo;


        

        marcador = "";
        proximo = "";

        if (nivelAtual > 0)
        {
            while (nivel < nivelAtual - 1)
            {
                entrou = false;
                for (it_rev = it; it_rev != this->mFilaImpressao.rend(); it_rev++)
                {
                    if ((*it_rev)->getNivel() == nivelAux - 1)
                    {
                        marcador = " |   " + marcador;
                        entrou = true;
                        break;
                    }
                    else if ((*it_rev)->getNivel() < nivelAux - 1)
                    {
                        break;
                    }
                }
                nivelAux--;
                nivel++;
                if (entrou == false) marcador = "     " + marcador;
            }
        }

        if (imprimir == true) { imprimir = false; saida << marcador << " |\n"; }

        if (nivelAtual > 0) saida << marcador << " |---";

        if ((*it)->temFilho() == true)
            saida << "[+] ";
        else
             saida << "--> ";

        if ((*it)->getConteudo() != NULL)
            saida << (*it)->getConteudo() << std::endl;
        else
        {
            std::list<std::string>::iterator i;
            std::list<std::string> *lista = (*it)->getExpressao();

            for (i = lista->begin(); i != lista->end(); i++)
                saida << (*i) << " ";
            saida << std::endl;
        }
        


/*-------------- exibe o pai do noh -------------------

        if ((*it)->getNoPai() == NULL)
            saida << (*it)->getConteudo() << " | raiz da arvore\n";
        else
        {
            NoArvore *a = (*it)->getNoPai();
            saida << (*it)->getConteudo() << " | pai: " << a->getConteudo() << "\n";
        }
*/
        if ( ((++it)) != this->mFilaImpressao.rend())
        {
            if ((*it)->getNivel() < nivelAtual)
                saida << marcador << "\n";

            else if ((*it)->getNivel() == nivelAtual)
               saida << marcador << " |"<< "\n";

            else if ((*it)->getNivel() > nivelAtual)
                imprimir = true;

        }
        it--;
        
    }
    saida << "\n\n";
}

/*--------------------------------------------
  Insere noAtual na fila de impressao
---------------------------------------------*/
void Arvore::inserirFilaImpressao(NoArvore *noAtual)
{
    std::list<NoArvore*>::reverse_iterator it;
    std::list<NoArvore*> *filhos = NULL;

    if (noAtual->temFilho())
    {
        filhos = noAtual->getFilhos();
        for (it = filhos->rbegin(); it != filhos->rend(); it++)
        {
            this->inserirFilaImpressao((*it));
        }
    }

    this->mFilaImpressao.push_back(noAtual);
}


/*--------------------------------------------
  Carrega a fila de impressao
---------------------------------------------*/
bool Arvore::carregarFilaImpressao()
{
    if (this->raiz == NULL) return false;
    
    if (this->mFilaImpressao.size() != 0)
        this->mFilaImpressao.clear();

    this->inserirFilaImpressao(this->raiz);
    
    return true;
}
